﻿using System.Runtime.InteropServices;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;

namespace RayDen.RayEngine.Core.Types
{
    [StructLayout(LayoutKind.Explicit)]
    public struct RayData : IRay
    {
        public const float RayEpsilon = 1e-4f;
        [FieldOffset(0)]
        public Point Org;
        [FieldOffset(12)]
        public Vector Dir;
        [FieldOffset(24)]
        public float minT;
        [FieldOffset(28)]
        public float maxT;

        public RayData(IRay r)
        {
            this.Org = r.Origin;
            this.Dir = r.Direction;
            this.maxT = r.Max;
            this.minT = r.Min;
        }
        public RayData(Point o, Vector d, float t1, float t2)
        {
            this.Org = o;
            this.Dir = d;
            this.Dir.Normalize();
            this.minT = t1;
            this.maxT = t2;
        }
        public RayData(ref Point o,ref Vector d, float t1, float t2)
        {
            this.Org = o;
            this.Dir = d;
            this.Dir.Normalize();
            this.minT = t1;
            this.maxT = t2;
        }
        public RayData(Point oor, Vector d)
        {
            Org = oor;
            Dir = d;
            this.Dir.Normalize();
            minT = 1e-4f;
            maxT = 1e4f;
        }
        public RayData(ref Point oor, ref Vector d)
        {
            Org = oor;
            Dir = d;
            this.Dir.Normalize();
            minT = 1e-4f;
            maxT = 1e4f;
        }
        public Point Origin { get { return Org; }       private set { Org = value; } }
        public Vector Direction { get { return Dir; }   private set { Dir = value; } }
        public Vector InvDirection { get { return 1f / Dir; } private set { } }

        public float Min { get { return minT; }  }
        public float Max { get { return maxT; }  }

        public Point Point(float t)
        {
            return new Point() { x = Org.x + Dir.x * t, y = Org.y + Dir.y * t, z = Org.z + Dir.z * t };
        }

        public void SetSegment(float min, float max)
        {
            //Min = min;
            //Max = max;
        }

        public void ApplyTransform(Transform m)
        {
            this.Org = m & this.Org;
            this.Dir = m & this.Dir;
        }
    } ;
}
